package com.youlai.boot.system.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.youlai.boot.core.security.util.SecurityUtils;
import com.youlai.boot.system.enums.RecycleStatusEnum;
import com.youlai.boot.system.enums.RoleTypeEnum;
import com.youlai.boot.system.mapper.*;
import com.youlai.boot.system.model.dto.AuditRequestDTO;
import com.youlai.boot.system.model.entity.*;
import com.youlai.boot.system.model.query.RecycleRequestQuery;
import com.youlai.boot.system.model.vo.RecycleRequestVO;
import com.youlai.boot.system.model.vo.ValueLabelVO;
import com.youlai.boot.system.service.RecyclePointsService;
import com.youlai.boot.system.service.RequestManagerService;
import com.youlai.boot.system.service.TransactionService;
import com.youlai.boot.system.service.UserPointsService;
import lombok.RequiredArgsConstructor;
import org.jetbrains.annotations.NotNull;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.annotation.Propagation;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.stream.Collectors;
import java.util.Collections;

import com.youlai.boot.system.service.NoticeService;
import com.youlai.boot.system.converter.NoticeConverter;
import com.youlai.boot.system.model.form.NoticeForm;
import com.youlai.boot.system.model.entity.Notice;

/**
 * @author 张雨润
 * @date 2025/2/25 21:26
 * @Description回收申请
 */
@Service
@RequiredArgsConstructor
public class RequestManagerServiceImpl extends ServiceImpl<RecycleRequestMapper, RecycleRequest>
        implements RequestManagerService {
    // 主表
    private final RecycleRequestMapper recycleRequestMapper;
    // 关联表
    private final RequestWasteMapper requestWasteMapper;
    // 垃圾类型表
    private final WasteTypeMapper wasteTypeMapper;

    private final UserMapper userMapper;

    private final UserRoleMapper userRoleMapper;

    private final RoleMapper roleMapper;

    private final OrgMapper orgMapper;

    private final TaskAssignmentMapper taskAssignmentMapper;

    private final TransactionService transactionService;

    private final ProcessRecordMapper processRecordMapper;

    private final UserPointsService userPointsService;

    private final RecyclePointsMapper recyclePointsMapper;

    private final UserPointsMapper userPointsMapper;

    private final NoticeService noticeService;
    private final NoticeConverter noticeConverter;
    private final NoticeMapper noticeMapper;

    /**
     * 机构分页查询数据
     * 
     * @param queryParams
     * @return
     */
    @Override
    public IPage<RecycleRequestVO> getPage(RecycleRequestQuery queryParams) {
        // 1.创建分页对象
        Page<RecycleRequest> page = new Page<>(queryParams.getPageNum(), queryParams.getPageSize());
        // 2.构建机构方搜索条件
        LambdaQueryWrapper<RecycleRequest> queryWrapper = buildOrgSearchCondition(queryParams);

        // 3.查询主表数据
        IPage<RecycleRequest> recycleRequestPage = recycleRequestMapper.selectPage(page, queryWrapper);
        List<RecycleRequest> recycleRequests = recycleRequestPage.getRecords();

        // 创建分页结果对象
        Page<RecycleRequestVO> resultPage = new Page<>(page.getCurrent(), page.getSize(), page.getTotal());

        if (CollUtil.isNotEmpty(recycleRequests)) {
            List<RecycleRequestVO> voList = recycleRequests.parallelStream().map(item -> {
                RecycleRequestVO vo = new RecycleRequestVO();
                BeanUtil.copyProperties(item, vo);
                vo.setArea(List.of(item.getProvince(), item.getCity(), item.getCountry()));
                vo.setWasteList(new LambdaQueryChainWrapper<>(requestWasteMapper)
                        .eq(RequestWaste::getRequestId, item.getId()).list());
                // 修改createTime格式
                vo.setCreateTime(item.getCreateTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
                // 用户id
                vo.setUsername(userMapper.selectById(item.getUserId()).getUsername());
                // 机构id（如果是机构发起）
                if (item.getOrgId() != null) {
                    vo.setOrgName(orgMapper.selectById(item.getOrgId()).getOrgName());
                }
                return vo;
            }).collect(Collectors.toList());

            resultPage.setRecords(voList);
        }

        return resultPage;
    }

    /**
     * （机构）审核回收申请
     * 1.通过，指定配送人员（本机构），状态0-->1
     * 2.驳回，驳回原因，状态0-->3
     * 
     * @param dto
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean auditRecycleRequest(AuditRequestDTO dto) {
        RecycleRequest recycleRequest = recycleRequestMapper.selectById(dto.getRequestId());
        User user = userMapper.selectById(SecurityUtils.getUserId());

        if (dto.getAuditStatus() == 0) {
            // 通过审核
            handleApproveRequest(recycleRequest, dto, user);
        } else {
            // 驳回申请
            handleRejectRequest(recycleRequest, dto);
        }
        return true;
    }

    /**
     * 处理通过审核的请求
     */
    private void handleApproveRequest(RecycleRequest recycleRequest, AuditRequestDTO dto, User user) {
        if (recycleRequest.getStatus().equals(RecycleStatusEnum.PENDING_REVIEW.getCode())) {
            // 待审核 -> 待回收
            handlePendingToRecycle(recycleRequest, dto, user);
        } else if (recycleRequest.getStatus().equals(RecycleStatusEnum.RECYCLING.getCode())) {
            // 回收中 -> 已回收
            handleRecyclingToRecycled(recycleRequest, dto);
        } else if (recycleRequest.getStatus().equals(RecycleStatusEnum.CANCELING.getCode())) {
            // 取消中 -> 回退中/已取消
            handleCancelingToFinal(recycleRequest, dto);
        }
    }

    /**
     * 处理待审核到待回收的转换
     */
    private void handlePendingToRecycle(RecycleRequest recycleRequest, AuditRequestDTO dto, User user) {
        // 1.修改垃圾主表状态
        recycleRequest.setStatus(RecycleStatusEnum.PENDING_RECYCLE.getCode());
        recycleRequest.setOrgId(user.getOrgId());
        recycleRequest.setUpdateTime(LocalDateTime.now());
        recycleRequestMapper.updateById(recycleRequest);

        // 2.新建配送任务表
        TaskAssignment taskAssignment = TaskAssignment.builder()
                .requestId(dto.getRequestId())
                .courierId(dto.getCourierId())
                .assignedTime(LocalDateTime.now())
                .orgId(user.getOrgId())
                .build();
        taskAssignmentMapper.insert(taskAssignment);

        // 3.发送通知
        sendRequestApprovedNotice(recycleRequest, user);
    }

    /**
     * 处理回收中到已回收的转换
     */
    private void handleRecyclingToRecycled(RecycleRequest recycleRequest, AuditRequestDTO dto) {
        // 1.修改状态
        recycleRequest.setStatus(RecycleStatusEnum.RECYCLED.getCode());
        recycleRequest.setUpdateTime(LocalDateTime.now());
        recycleRequestMapper.updateById(recycleRequest);

        // 2.汇款交易
        TaskAssignment taskAssignment = taskAssignmentMapper.selectOne(
                new LambdaQueryWrapper<TaskAssignment>().eq(TaskAssignment::getRequestId, dto.getRequestId()));
        transactionService.transactionAmountToUser(taskAssignment, recycleRequest);

        // 3.新建处理记录
        if (dto.getOperatorId() != null) {
            ProcessRecord processRecord = ProcessRecord.builder()
                    .requestId(dto.getRequestId())
                    .operationId(dto.getOperatorId())
                    .processStatus(0)
                    .build();
            processRecordMapper.insert(processRecord);
        }

        // 4.记录用户积分
        recordUserPoints(recycleRequest);

        // 5.发送通知
        sendRecycleCompletedNotice(recycleRequest);
    }

    /**
     * 处理取消中到最终状态的转换
     */
    private void handleCancelingToFinal(RecycleRequest recycleRequest, AuditRequestDTO dto) {
        TaskAssignment taskAssignment = taskAssignmentMapper.selectOne(
                new LambdaQueryWrapper<TaskAssignment>().eq(TaskAssignment::getRequestId, dto.getRequestId()));

        // 如果该申请，存在垃圾回收任务，则需退回垃圾
        if (ObjectUtil.isNotEmpty(taskAssignment)) {
            // 如果已经上门回收，则需要退回垃圾
            boolean isReceived = taskAssignment.getIsReceived().equals(1);
            if (isReceived) {
                recycleRequest.setStatus(RecycleStatusEnum.ROLL_BACKING.getCode());
            } else {
                recycleRequest.setStatus(RecycleStatusEnum.CANCELED.getCode());
            }

            // 通知配送员取消任务
            sendRequestCanceledNoticetoWorker(recycleRequest, taskAssignment, isReceived);
        } else {
            recycleRequest.setStatus(RecycleStatusEnum.CANCELED.getCode());
        }

        recycleRequest.setUpdateTime(LocalDateTime.now());
        recycleRequestMapper.updateById(recycleRequest);

        // 发送通知给用户
        sendRequestCanceledNoticetoUser(recycleRequest);
    }

    /**
     * 处理驳回申请
     */
    private void handleRejectRequest(RecycleRequest recycleRequest, AuditRequestDTO dto) {
        // 1.修改状态
        recycleRequest.setStatus(RecycleStatusEnum.REJECTED.getCode());
        if (dto.getRejectReason() != null) {
            recycleRequest.setRejectReason(dto.getRejectReason());
        }
        recycleRequest.setUpdateTime(LocalDateTime.now());
        recycleRequestMapper.updateById(recycleRequest);

        // 2.发送通知
        sendRequestRejectedNotice(recycleRequest);
    }

    /**
     * 发送申请通过通知
     */
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
    protected void sendRequestApprovedNotice(RecycleRequest request, User user) {
        // 1. 发送给申请用户
        TaskAssignment taskAssignment = taskAssignmentMapper.selectOne(
                new LambdaQueryWrapper<TaskAssignment>().eq(TaskAssignment::getRequestId, request.getId()));
        String courierInfo = "";
        if (taskAssignment != null) {
            User courier = userMapper.selectById(taskAssignment.getCourierId());
            if (courier != null) {
                courierInfo = String.format("<p style='margin: 10px 0;'><strong>配送员姓名：</strong>%s</p>" +
                        "<p style='margin: 10px 0;'><strong>配送员电话：</strong>%s</p>",
                        courier.getUsername(),
                        courier.getMobile());
            }
        }

        NoticeForm form = NoticeForm.builder()
                .title("回收申请已通过")
                .content(String.format(
                        "<div style='font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto; padding: 20px; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.1);'>"
                                +
                                "<h2 style='color: #4CAF50; margin-bottom: 20px;'>申请通过通知</h2>" +
                                "<div style='background-color: #f9f9f9; padding: 15px; border-radius: 5px;'>" +
                                "<p style='margin: 10px 0;'><strong>申请编号：</strong>%s</p>" +
                                "<p style='margin: 10px 0;'><strong>处理机构：</strong>%s</p>" +
                                "<p style='margin: 10px 0;'><strong>处理时间：</strong>%s</p>" +
                                "%s" +
                                "</div>" +
                                "<p style='margin-top: 20px; color: #666;'>您的回收申请已通过审核，我们将尽快安排人员上门回收。</p>" +
                                "</div>",
                        request.getId(),
                        user.getOrgId() != null ? orgMapper.selectById(user.getOrgId()).getOrgName() : "系统",
                        LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")),
                        courierInfo))
                .level("L")
                .targetType(2)
                .type(3)
                .targetUserIds(Collections.singletonList(String.valueOf(request.getUserId())))
                .build();

        Notice entity = noticeConverter.toEntity(form);
        entity.setCreateBy(user.getId());
        entity.setPublisherId(user.getId());
        noticeMapper.insert(entity);
        noticeService.publishNotice(entity.getId());

        // 2. 发送给需要上门回收的配送员
        if (taskAssignment != null) {
            NoticeForm courierForm = NoticeForm.builder()
                    .title("新的回收任务")
                    .content(String.format(
                            "<div style='font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto; padding: 20px; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.1);'>"
                                    +
                                    "<h2 style='color: #409EFF; margin-bottom: 20px;'>新任务通知</h2>" +
                                    "<div style='background-color: #f9f9f9; padding: 15px; border-radius: 5px;'>" +
                                    "<p style='margin: 10px 0;'><strong>任务编号：</strong>%s</p>" +
                                    "<p style='margin: 10px 0;'><strong>回收地址：</strong>%s</p>" +
                                    "<p style='margin: 10px 0;'><strong>预约时间：</strong>%s</p>" +
                                    "<p style='margin: 10px 0;'><strong>联系电话：</strong>%s</p>" +
                                    "</div>" +
                                    "<p style='margin-top: 20px; color: #666;'>请及时联系用户并按时上门回收。</p>" +
                                    "</div>",
                            request.getId(),
                            request.getProvince() + request.getCity() + request.getCountry() + request.getAddress(),
                            request.getRecycleTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")),
                            request.getMobile()))
                    .level("M")
                    .targetType(2)
                    .type(4)
                    .targetUserIds(Collections.singletonList(String.valueOf(taskAssignment.getCourierId())))
                    .build();

            Notice courierEntity = noticeConverter.toEntity(courierForm);
            courierEntity.setCreateBy(user.getId());
            courierEntity.setPublisherId(user.getId());
            noticeMapper.insert(courierEntity);
            noticeService.publishNotice(courierEntity.getId());
        }
    }

    /**
     * 发送回收完成通知
     */
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
    protected void sendRecycleCompletedNotice(RecycleRequest request) {
        // 1. 通知用户已经回收成功
        NoticeForm form = NoticeForm.builder()
                .title("回收已完成")
                .content(String.format(
                        "<div style='font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto; padding: 20px; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.1);'>"
                                +
                                "<h2 style='color: #4CAF50; margin-bottom: 20px;'>回收完成通知</h2>" +
                                "<div style='background-color: #f9f9f9; padding: 15px; border-radius: 5px;'>" +
                                "<p style='margin: 10px 0;'><strong>申请编号：</strong>%s</p>" +
                                "<p style='margin: 10px 0;'><strong>完成时间：</strong>%s</p>" +
                                "<p style='margin: 10px 0;'><strong>预计收益：</strong>¥%s</p>" +
                                "<p style='margin: 10px 0;'><strong>处理人员：</strong>%s</p>" +
                                "</div>" +
                                "<p style='margin-top: 20px; color: #666;'>您的回收订单已完成，收益已打入账户。后续将由处理人员进行垃圾处理工作。</p>" +
                                "</div>",
                        request.getId(),
                        LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")),
                        request.getExpectReturn(),
                        request.getOrgId() != null ? orgMapper.selectById(request.getOrgId()).getOrgName() : "系统"))
                .level("L")
                .targetType(2)
                .type(3)
                .targetUserIds(Collections.singletonList(String.valueOf(request.getUserId())))
                .build();

        Notice entity = noticeConverter.toEntity(form);
        entity.setCreateBy(request.getUserId());
        entity.setPublisherId(request.getUserId());
        noticeMapper.insert(entity);
        noticeService.publishNotice(entity.getId());

        // 2. 通知垃圾处理员进行垃圾处理任务
        if (request.getOrgId() != null) {
            // 查找机构下的处理员
            List<User> processors = userMapper.selectList(
                    new LambdaQueryWrapper<User>()
                            .eq(User::getOrgId, request.getOrgId()))
                    .stream()
                    .filter(u -> {
                        Long roleId = userRoleMapper.selectOne(
                                new QueryWrapper<UserRole>()
                                        .eq("user_id", u.getId()))
                                .getRoleId();
                        String code = roleMapper.selectById(roleId).getCode();
                        return RoleTypeEnum.WORKER.getCode().equals(code);
                    }).toList();

            if (!processors.isEmpty()) {
                User processor = processors.get(0);
                NoticeForm processorForm = NoticeForm.builder()
                        .title("新的垃圾处理任务")
                        .content(String.format(
                                "<div style='font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto; padding: 20px; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.1);'>"
                                        +
                                        "<h2 style='color: #409EFF; margin-bottom: 20px;'>新任务通知</h2>" +
                                        "<div style='background-color: #f9f9f9; padding: 15px; border-radius: 5px;'>" +
                                        "<p style='margin: 10px 0;'><strong>任务编号：</strong>%s</p>" +
                                        "<p style='margin: 10px 0;'><strong>垃圾类型：</strong>%s</p>" +
                                        "<p style='margin: 10px 0;'><strong>处理时间：</strong>%s</p>" +
                                        "</div>" +
                                        "<p style='margin-top: 20px; color: #666;'>请及时处理回收的垃圾。</p>" +
                                        "</div>",
                                request.getId(),
                                new LambdaQueryChainWrapper<>(requestWasteMapper)
                                        .eq(RequestWaste::getRequestId, request.getId())
                                        .list()
                                        .stream()
                                        .map(rw -> {
                                            WasteType wasteType = wasteTypeMapper.selectById(rw.getTypeId());
                                            return wasteType != null ? wasteType.getTypeName() : "";
                                        })
                                        .filter(StrUtil::isNotBlank)
                                        .collect(Collectors.joining("、")),
                                LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))))
                        .level("M")
                        .targetType(2)
                        .type(4)
                        .targetUserIds(Collections.singletonList(String.valueOf(processor.getId())))
                        .build();

                Notice processorEntity = noticeConverter.toEntity(processorForm);
                processorEntity.setCreateBy(request.getUserId());
                processorEntity.setPublisherId(request.getUserId());
                noticeMapper.insert(processorEntity);
                noticeService.publishNotice(processorEntity.getId());
            }
        }
    }

    /**
     * 发送申请驳回通知
     */
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
    protected void sendRequestRejectedNotice(RecycleRequest request) {
        NoticeForm form = NoticeForm.builder()
                .title("回收申请已驳回")
                .content(String.format(
                        "<div style='font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto; padding: 20px; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.1);'>"
                                +
                                "<h2 style='color: #F56C6C; margin-bottom: 20px;'>申请驳回通知</h2>" +
                                "<div style='background-color: #f9f9f9; padding: 15px; border-radius: 5px;'>" +
                                "<p style='margin: 10px 0;'><strong>申请编号：</strong>%s</p>" +
                                "<p style='margin: 10px 0;'><strong>驳回原因：</strong>%s</p>" +
                                "<p style='margin: 10px 0;'><strong>处理时间：</strong>%s</p>" +
                                "</div>" +
                                "<p style='margin-top: 20px; color: #666;'>如有疑问，请联系客服处理。</p>" +
                                "</div>",
                        request.getId(),
                        request.getRejectReason() != null ? request.getRejectReason() : "未提供具体原因",
                        LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))))
                .level("L")
                .targetType(2)
                .type(3)
                .targetUserIds(Collections.singletonList(String.valueOf(request.getUserId())))
                .build();

        Notice entity = noticeConverter.toEntity(form);
        entity.setCreateBy(request.getUserId());
        entity.setPublisherId(request.getUserId());
        noticeMapper.insert(entity);
        noticeService.publishNotice(entity.getId());
    }

    /**
     * 发送申请取消通知给用户
     */
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
    protected void sendRequestCanceledNoticetoUser(RecycleRequest request) {
        NoticeForm form = NoticeForm.builder()
                .title("回收申请已取消")
                .content(String.format(
                        "<div style='font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto; padding: 20px; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.1);'>"
                                +
                                "<h2 style='color: #909399; margin-bottom: 20px;'>申请取消通知</h2>" +
                                "<div style='background-color: #f9f9f9; padding: 15px; border-radius: 5px;'>" +
                                "<p style='margin: 10px 0;'><strong>申请编号：</strong>%s</p>" +
                                "<p style='margin: 10px 0;'><strong>取消时间：</strong>%s</p>" +
                                "<p style='margin: 10px 0;'><strong>当前状态：</strong>%s</p>" +
                                "</div>" +
                                "<p style='margin-top: 20px; color: #666;'>您的回收申请已取消。</p>" +
                                "</div>",
                        request.getId(),
                        LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")),
                        request.getStatus().equals(RecycleStatusEnum.ROLL_BACKING.getCode()) ? "回退中" : "已取消"))
                .level("L")
                .targetType(2)
                .type(3)
                .targetUserIds(Collections.singletonList(String.valueOf(request.getUserId())))
                .build();

        Notice entity = noticeConverter.toEntity(form);
        entity.setCreateBy(request.getUserId());
        entity.setPublisherId(request.getUserId());
        noticeMapper.insert(entity);
        noticeService.publishNotice(entity.getId());
    }

    /**
     * 发送申请取消通知给工作人员
     */
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
    protected void sendRequestCanceledNoticetoWorker(RecycleRequest recycleRequest, TaskAssignment taskAssignment,
            boolean isReceived) {
        String actionMessage = isReceived ? "<p style='margin-top: 20px; color: #666;'>该回收任务已被取消，请将已回收的垃圾退回给用户。</p>"
                : "<p style='margin-top: 20px; color: #666;'>该回收任务已被取消，请停止上门回收服务。</p>";

        NoticeForm courierForm = NoticeForm.builder()
                .title("回收任务已取消")
                .content(String.format(
                        "<div style='font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto; padding: 20px; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.1);'>"
                                +
                                "<h2 style='color: #FF4D4F; margin-bottom: 20px;'>任务取消通知</h2>" +
                                "<div style='background-color: #f9f9f9; padding: 15px; border-radius: 5px;'>" +
                                "<p style='margin: 10px 0;'><strong>任务编号：</strong>%s</p>" +
                                "<p style='margin: 10px 0;'><strong>取消时间：</strong>%s</p>" +
                                "<p style='margin: 10px 0;'><strong>回收地址：</strong>%s</p>" +
                                "<p style='margin: 10px 0;'><strong>当前状态：</strong>%s</p>" +
                                "</div>" +
                                "%s" +
                                "</div>",
                        recycleRequest.getId(),
                        LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")),
                        recycleRequest.getProvince() + recycleRequest.getCity() + recycleRequest.getCountry()
                                + recycleRequest.getAddress(),
                        isReceived ? "需要退回垃圾" : "已取消任务",
                        actionMessage))
                .level("M")
                .targetType(2)
                .type(4)
                .targetUserIds(Collections.singletonList(String.valueOf(taskAssignment.getCourierId())))
                .build();
        Notice courierEntity = noticeConverter.toEntity(courierForm);
        courierEntity.setCreateBy(recycleRequest.getUserId());
        courierEntity.setPublisherId(recycleRequest.getUserId());
        noticeMapper.insert(courierEntity);
        noticeService.publishNotice(courierEntity.getId());
    }

    /**
     * 记录用户积分
     * 1. 计算总回收获得的积分
     * 2. 对积分进行记录
     * 3. 对用户积分进行累加
     * 
     * @param recycleRequest
     */
    private void recordUserPoints(RecycleRequest recycleRequest) {
        // 1.计算积分
        List<RequestWaste> wasteList = requestWasteMapper
                .selectList(new QueryWrapper<RequestWaste>().eq("request_id", recycleRequest.getId()));
        BigDecimal totalPoints = BigDecimal.ZERO;
        for (RequestWaste rw : wasteList) {
            Long typeId = rw.getTypeId();
            if (typeId == null) {
                continue; // 跳过无效的废品类型
            }
            WasteType wasteType = wasteTypeMapper.selectById(typeId);
            BigDecimal pointsPerKg = wasteType.getPointsPerKg();
            BigDecimal weight = rw.getWeight();
            BigDecimal points = pointsPerKg.multiply(weight);
            totalPoints = totalPoints.add(points);
        }
        // 2.对此次回收积分来源进行记录
        RecyclePoints recyclePoints = RecyclePoints.builder()
                .userId(recycleRequest.getUserId())
                .requestId(recycleRequest.getId())
                .points(totalPoints)
                .build();
        recyclePointsMapper.insert(recyclePoints);
        // 3.对用户积分计算累计
        UserPoints userPoints = userPointsMapper
                .selectOne(new QueryWrapper<UserPoints>().eq("user_id", recycleRequest.getUserId()));
        if (ObjectUtil.isNull(userPoints)) {
            userPoints = UserPoints.builder()
                    .userId(recycleRequest.getUserId())
                    .totalPoints(totalPoints)
                    .remainPoints(totalPoints)
                    .build();
            userPointsService.save(userPoints);
        } else {
            userPoints.setTotalPoints(userPoints.getTotalPoints().add(totalPoints));
            userPoints.setRemainPoints(userPoints.getRemainPoints().add(totalPoints));
            userPointsService.updateById(userPoints);
        }
    }

    /**
     * 隶属本机构的配送人员名单
     * 
     * @return
     */
    @Override
    public List<ValueLabelVO> getOrgWorkers() {
        Long userId = SecurityUtils.getUserId();
        if (userId != null) {
            User user = userMapper.selectById(userId);
            if (user.getOrgId() != null) {
                List<User> users = userMapper
                        .selectList(new LambdaQueryWrapper<User>().eq(User::getOrgId, user.getOrgId()));
                return users.stream().filter(f -> {
                    Long roleId = userRoleMapper
                            .selectOne(new LambdaQueryWrapper<UserRole>().eq(UserRole::getUserId, f.getId()))
                            .getRoleId();
                    String code = roleMapper.selectById(roleId).getCode();
                    return RoleTypeEnum.WORKER.getCode().equals(code);
                }).map(item -> new ValueLabelVO(item.getId().toString(), item.getUsername()))
                        .toList();
            }
        }
        return List.of();
    }

    /**
     * 机构查询已回收请求
     * 
     * @param queryParams
     * @return
     */
    @Override
    public IPage<RecycleRequestVO> getPageRecycled(RecycleRequestQuery queryParams) {
        // 1.创建分页对象
        Page<RecycleRequest> page = new Page<>(queryParams.getPageNum(), queryParams.getPageSize());
        // 2.构建机构方搜索条件
        LambdaQueryWrapper<RecycleRequest> queryWrapper = buildOrgSearchCondition(queryParams);
        queryWrapper.eq(RecycleRequest::getStatus, RecycleStatusEnum.RECYCLED.getCode());
        // 3.查询主表数据
        IPage<RecycleRequest> recycleRequestPage = recycleRequestMapper.selectPage(page, queryWrapper);
        List<RecycleRequest> recycleRequests = recycleRequestPage.getRecords();

        // 创建分页结果对象
        Page<RecycleRequestVO> resultPage = new Page<>(page.getCurrent(), page.getSize(), page.getTotal());

        if (CollUtil.isNotEmpty(recycleRequests)) {
            List<RecycleRequestVO> voList = recycleRequests.parallelStream().map(item -> {
                RecycleRequestVO vo = new RecycleRequestVO();
                BeanUtil.copyProperties(item, vo);
                vo.setArea(List.of(item.getProvince(), item.getCity(), item.getCountry()));
                vo.setWasteList(new LambdaQueryChainWrapper<>(requestWasteMapper)
                        .eq(RequestWaste::getRequestId, item.getId()).list());
                // 修改createTime格式
                vo.setCreateTime(item.getCreateTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
                // 用户id
                vo.setUsername(userMapper.selectById(item.getUserId()).getUsername());
                // 机构id（如果是机构发起）
                if (item.getOrgId() != null) {
                    vo.setOrgName(orgMapper.selectById(item.getOrgId()).getOrgName());
                }
                return vo;
            }).collect(Collectors.toList());

            resultPage.setRecords(voList);
        }

        return resultPage;
    }

    /**
     * 构建机构方查询条件
     * 
     * @param queryParams
     * @return
     */
    @NotNull
    private LambdaQueryWrapper<RecycleRequest> buildOrgSearchCondition(RecycleRequestQuery queryParams) {
        LambdaQueryWrapper<RecycleRequest> queryWrapper = new LambdaQueryWrapper<>();

        // 2.1.查询含有该用户名的userId
        if (StrUtil.isNotBlank(queryParams.getUsername())) {
            List<Long> userIds = userMapper
                    .selectList(new QueryWrapper<User>().like("username", queryParams.getUsername()).select("id"))
                    .stream()
                    .map(User::getId)
                    .collect(Collectors.toList());
            queryWrapper.in(RecycleRequest::getUserId, userIds);
        }
        // 2.2.查询含有该机构名的orgId
        if (StrUtil.isNotBlank(queryParams.getOrgName())) {
            List<Long> orgIds = orgMapper
                    .selectList(new QueryWrapper<Org>().like("org_name", queryParams.getOrgName()).select("id"))
                    .stream()
                    .map(Org::getId)
                    .collect(Collectors.toList());
            queryWrapper.in(RecycleRequest::getOrgId, orgIds);
        }
        // 2.3主表状态
        if (CollUtil.isNotEmpty(queryParams.getStatus())) {
            queryWrapper.in(RecycleRequest::getStatus, queryParams.getStatus());
        }
        // 2.4期望收益区间
        if (queryParams.getMinExpectReturn() != null) {
            queryWrapper.ge(RecycleRequest::getExpectReturn, queryParams.getMinExpectReturn());
        }
        if (queryParams.getMaxExpectReturn() != null) {
            queryWrapper.le(RecycleRequest::getExpectReturn, queryParams.getMaxExpectReturn());
        }
        // 2.5创建时间
        if (queryParams.getCreateTimeStart() != null) {
            queryWrapper.ge(RecycleRequest::getCreateTime, queryParams.getCreateTimeStart());
        }
        if (queryParams.getCreateTimeEnd() != null) {
            queryWrapper.le(RecycleRequest::getCreateTime, queryParams.getCreateTimeEnd());
        }
        // 2.6联系方式
        if (StrUtil.isNotBlank(queryParams.getMobile())) {
            queryWrapper.like(RecycleRequest::getMobile, queryParams.getMobile());
        }
        queryWrapper.orderByDesc(RecycleRequest::getUpdateTime);
        return queryWrapper;
    }

}
